package list.arraylist;

import custom_class.Person;
import custom_class.PersonComparator;

import java.util.*;

/**
 * @author wenyuan
 * @version 1.0
 * @date 2023/7/18
 * @since 8
 */
public class TArrayList  {

    static ArrayList<Object> arrayList1 = new ArrayList<Object>();
    static ArrayList<Object> arrayList2 = new ArrayList<Object>();

    public static void main(String[] args) {
        permitAllType();     // 1. 允许所有类型
        // operateBasically();     // 2. 支持的所有基本操作
        // iterate();      // 3. 遍历
        // otherMethod();       // 4. 其他方法
       // cloneUnderlyingly();    // 5. 拷贝接口的底层细节
        compareTo();        // 6. 关于排序的用法
    }

    /**
     * 这个方法说明一件事： ArrayList 支持所有类型继承 Object 的类型，因为它存储元素的容器是 Object[]
     */
    private static void permitAllType() {
        arrayList1.add(0, 1);
        arrayList1.add(1, 13.21);
        arrayList1.add(2, "你好！");
        arrayList1.add(3, new Person(175, 62, 21, "男"));
        // System.out.println(arrayList1);
    }

    /**
     * 关于基石操作，如 get, contains, equals,  add, remove, indexOf, set
     */
    private static void operateBasically() {
        Object o = arrayList1.get(3);
        System.out.println(o);

        boolean contains = arrayList1.contains("你好！");
        System.out.println("arrayList1" + (contains ? "存在" : "不存在") + "你好！");

        boolean equals = arrayList1.equals(arrayList2);
        System.out.println("arrayList1 与 arrayList2" + (equals ? "相等" : "不相等"));

        boolean remove = arrayList1.remove("1");
        Object removeByIndex = arrayList1.remove(1);
        System.out.println("arrayList1 的这个元素删除" + (remove ? "成功" : "失败"));
        System.out.println("arrayList1 的这个元素删除的是" + removeByIndex);

        int indexOf = arrayList1.indexOf("你好！");
        System.out.println("arrayList1 中 你好！ 在第" + (indexOf + 1) + "位");

        Object set = arrayList1.set(0, "世界，");
        // Object exceptionOrInsertion = arrayList1.set(3, "像你这样的人，");     // exception
        System.out.println("修改 arrayList1 的 第一个元素 它的原值是" + set);
        // System.out.println("修改 arrayList1 的 第四个元素为" + exceptionOrInsertion );
    }

    /**
     * 遍历 五种
     */
    private static void iterate() {
        // 1. for (...;...;...){} 经典
        for (int i = 0; i < arrayList1.size(); i++) {
            System.out.println(arrayList1.get(i));
        }
        System.out.println("----------------------------");

        // 2. for(? : ?)
        for (Object o : arrayList1) {
            System.out.println(o);
        }
        System.out.println("----------------------------");

        // 3. forEach遍历，内部等同于 for (...;...;...){} 不过加了并发控制（使用了一个数是否被改变（循环一次就判断））
        arrayList1.forEach(System.out::println);
        System.out.println("----------------------------");

        // 4. stream
        long count = arrayList1.stream()
                .skip(1)
                .count();
        System.out.println("跳过第一个元素后还有" + count + "个元素");
        System.out.println("----------------------------");
        // 5. iterator
        Iterator<Object> iterator = arrayList1.iterator();
        while (iterator.hasNext()) {
            Object next = iterator.next();
            System.out.println(next);
        }
    }

    /**
     * 克隆，也就是创建一个对象并为这个对象赋予属性，这用到了 Prototype （原型模式）
     * clone: 返回一个浅拷贝的对象
     * 浅拷贝： 目标对象整个框架会得到new, 但它的目标对象里的引用 不会new一个 只会得到它的引用拷贝
     * 引用拷贝： 不会new 只会new该引用然后拷贝相同目标引用，结果引用跟目标引用是保存的值是相同的地址，
     * 深拷贝： 所有属性都是new的
     * <p>
     * 要使用 Clone 必须要有该类 继承了 Cloneable 接口
     *
     * 注意： Cloneable 都没有任何方法，完全就是一个标志性的东西， clone 方法在顶级父类 Object 里
     * 续： 而 Object 压根没有继承 Cloneable 接口，但该方法是被 native 修饰的，是被其他语言实现的或其他什么的实现的外部库
     */
    private static void cloneUnderlyingly() {
        Object clone = arrayList1.clone();
        System.out.println(clone);

        // Person throws exception
        Person person = new Person();
        Person clonedPerson = person.clone();
        System.out.println(clonedPerson);
        // 直接创建 Object 对象调用 clone 抛出异常，没想到 clone 还是被 protected 修饰的，所以只能通过继承且放同一包内才行
        // 换到 java.lang 包下测试一下,
        // 测不了，没想到， prohibited package name java.lang 🤗

        // 但可以在 Person 上测试一下，继承 Cloneable
    }

    /**
     *
     */
    private static void otherMethod() {
        List<Object> objects = arrayList1.subList(2, 4);
        System.out.println("切割一部分元素出来的列表是" + objects);
    }

    /**
     * 比较的两种方式是怎么搞的
     * 第一种： 使用集合框架里的集合时，调用 sort，创建匿名内部内的Comparator
     * 第二种： 使用集合框架里的集合时，调用 sort，创建一个 实现 Comparator 接口的自定义比较器
     * 第三种： 比较类，实现 Comparable 接口，然后可以利用工具类提供的排序方法
     * 第一种： 不适合复用，但来得快
     * 第二种： 可以比较任意规则，适合需要比较的比较多的功能
     * 第三种： 只适合比较本类的简单数组，非对象数组，适用于要将该类存到集合里去，比如Integer Double等包装类型，被那些需要比较的集合类视作根本接口
     * 注意： 其实三种都是使用到了工具类提供的排序算法，只不过第三种和前两种有细微差别
     */
    private static void compareTo(){

        ArrayList<Person> arrayList3 = new ArrayList<>();
        arrayList3.add(new Person(164, 55, 21, "女"));
        arrayList3.add(new Person(178, 78, 24, "男"));
        arrayList3.add(new Person(168, 52, 19, "女"));
        for(Person person : arrayList3){
            System.out.println(person);
        }

        System.out.println("--------------排序后-------------");
        // 第一种： 使用集合框架里的集合时，调用 sort，创建匿名内部内的Comparator
        // arrayList3.sort(new PersonComparator<Object>() {
        //     @Override
        //     public int compare(Object o1, Object o2) {
        //         Person p1 = (Person)o1;
        //         Person p2 = (Person) o2;
        //         if(p1.getAge() > p2.getAge())
        //             return 1;
        //         else return -1;
        //     }
        // });


        // 第二种： 使用集合框架里的集合时，调用 sort，创建一个 实现 Comparator 接口的自定义比较器
        arrayList3.sort(new PersonComparator());
        for(Object person : arrayList3){
            System.out.println(person);
        }

        // 第三种： 比较类，实现 Comparable 接口
        System.out.println();
        System.out.println();
        Person[] people = {new Person(164, 55, 21, "女")
                , new Person(178, 78, 24, "男")
                , new Person(178, 78, 22, "男")};
        for(Person person : people){
            System.out.println(person);
        }
        Arrays.sort(people);
        System.out.println("排序后");
        for(Person person : people){
            System.out.println(person);
        }
    }

}
